Smartseq2 method. reads aligned to mm10-plus.
Read the gene cell table that has the read_count for every gene and cell:
setwd("/Volumes/GoogleDrive/My Drive/research/Mu_He/sequencing")
Trachea_May<-read.csv(file="180516_NS500126_0797_AHMCKKBGX5.csv",header=TRUE,sep=",")
Remove the first column (gene names), and convert the gene names to rownames of the dataframe
dfTrachea_May<-as.data.frame(Trachea_May[,-1])
rownames(dfTrachea_May)<-Trachea_May[,1]
Remove the last column (“undetermined” reads)
dfTrachea_May<-dfTrachea_May[,-705] #remove the "undetermined" column
got a dataframe of 704 variables (columns),because we have 2 plates each have 352 “cells”. Each of the column in the dataframe is a cell
Also this dataframe has 23438 observations (rows), each of which is a gene
library(dplyr)
package ‘dplyr’ was built under R version 3.4.4
Attaching package: ‘dplyr’
The following objects are masked from ‘package:stats’:
filter, lag
The following objects are masked from ‘package:base’:
intersect, setdiff, setequal, union
Specify the rawdata to be taken by Seurat:
raw.data<-dfTrachea_May
analyze ERCC:
get all rownames that contain “ERCC”:
erccs <- grep(pattern = "^ERCC-", x = rownames(x = raw.data), value = TRUE)
calculate the percentage of ERCC reads in total reads for each cell, and plot:
percent.ercc <- Matrix::colSums(raw.data[erccs, ])/Matrix::colSums(raw.data)
df_ercc<-as.data.frame(cbind(colnames(raw.data),as.numeric(percent.ercc)))
ggplot(df_ercc,aes(percent.ercc))+geom_density()
Get the row index for ERCCs:
ercc.index <- grep(pattern = "^ERCC-", x = rownames(x = raw.data), value = FALSE)
Now create seurat object.
seuTrachea_May <- CreateSeuratObject(raw.data = raw.data, project = "Trachea_May_mouse8",
min.cells = 1, min.genes = 500)
dim(seuTrachea_May@raw.data)
So I have 523 “cells” in which at least 500 genes are detected. 18157 “genes” are detected in at least 1 “cell”
Now analyze ribosome genes:
generate a list of ribo gene names:
ribo.genes <- grep(pattern = "^Rp[sl][[:digit:]]", x = rownames(x = seuTrachea_May@data), value = TRUE)
calculate their ratio for every cell:
percent.ribo <- Matrix::colSums(seuTrachea_May@raw.data[ribo.genes, ])/Matrix::colSums(seuTrachea_May@raw.data)
sanity check:
VlnPlot(object = seuTrachea_May, features.plot = c("nGene", "nReads", "percent.ercc","percent.ribo"), nCol = 4,x.lab.rot = TRUE)
GenePlot(object = seuTrachea_May, gene1 = "nReads", gene2 = "nGene", use.raw=T)
Now remove the cells with too few reads <100k and too few genes <500
seuTrachea_May <- FilterCells(object = seuTrachea_May, subset.names = c("nGene", "nReads"),
low.thresholds = c(500, 100000), high.thresholds = c(Inf, Inf))
dim(seuTrachea_May@data)
The above generats object@var.genes, which is a vector of gene names that are identified to be variable. y.cutoff decides the cutoff for being “variable”.
The result of all analysis is stored in object@hvg.info. A plot is also generated, with “variable” genes labeled with names.
Returns Seurat object with the PCA calculation stored in object@dr$pca. In the function below, if do.print=TRUE, genes in each PC will be shown.
seuTrachea_May <- RunPCA(object = seuTrachea_May, do.print = FALSE)
PCAPlot(seuTrachea_May)
Another way to show major genes in major PCs:
PrintPCA(seuTrachea_May, pcs.print = 1:5, genes.print = 5, use.full = TRUE)
Below is another way to see PCs and how they separate the data: cells and genes are ordered according to their PCA scores. Setting cells.use (for example: cell.use=100) to a number plots the ‘extreme’ cells on both ends of the spectrum, which dramatically speeds plotting for large datasets (but will ignore the cells in the middle). num.genes=30 by default.
PCHeatmap(object = seuTrachea_May, pc.use = 1:3, do.balanced = TRUE, label.columns = FALSE)
Now need to decide how many PCs to use:
PCElbowPlot(object = seuTrachea_May)
The above plot shows that the elbow of the graph falls at around pc 20.
Another way to statistically estimate: (caution: running this is slow)
seuTrachea_May <- JackStraw(seuTrachea_May, num.replicate = 100, do.print = FALSE)
JackStrawPlot(seuTrachea_May, PCs = 1:20)
n.pcs = 20
resolution parameter sets the ‘granularity’ of the downstream clustering, with increased values leading to a greater number of clusters.
res.used <- 1
K-nearest neighbor:
seuTrachea_May <- FindClusters(object = seuTrachea_May, reduction.type = "pca", dims.use = 1:n.pcs,
resolution = res.used, print.output = 0, force.recalc = T)
Now I can see how many cell passing filters from each plate.
tSNE: (perplexity default is 30)
seuTrachea_May <- RunTSNE(object = seuTrachea_May, dims.use = 1:n.pcs, perplexity=30)
TSNEPlot(object = seuTrachea_May, do.label = T)
TSNEPlot(object = seuTrachea_May, group.by="plate")
FeaturePlot(seuTrachea_May, c("nGene","Gfp_transgene","Tdtom_transgene","Shh","Ano1","Epcam","Lum","Aurkb","Matn4","Esam","Actc1","Pax8"), pt.size = 0.9, nCol = 3,no.legend = F)
seuTrachea_May <- SetAllIdent(object = seuTrachea_May, id = "ident")
GenePlot(object = seuTrachea_May, gene1 = "Shh", gene2 = "Gfp_transgene", use.raw=T)
VlnPlot(object = seuTrachea_May, features.plot = c("Gfp_transgene","Tdtom_transgene", "Cre_transgene"), nCol = 3)
DoHeatmap(object = seuTrachea_May, genes.use = c("Tdtom_transgene","Cre_transgene", "Gfp_transgene","Shh","Ano1","Sox9"),
slim.col.label = TRUE, group.label.rot = TRUE)
find markers for every cluster compared to all remaining cells, report only the positive ones
cluster.markers <- FindAllMarkers(object=seuTrachea_May, min.pct = 0.2,only.pos=TRUE)
cluster.markers %>% group_by(cluster) %>% top_n(10, avg_logFC)
compare cluster 0 and 2
cluster0.markers.pos <- FindMarkers(seuTrachea_May, ident.1 = 0,ident.2 = 2, min.pct = 0,only.pos=TRUE)
print(cluster0.markers.pos)
cluster2.markers.pos <- FindMarkers(seuTrachea_May, ident.1 = 2,ident.2 = 0, min.pct = 0,only.pos=TRUE)
print(cluster2.markers.pos)
save the seurat project for future visit:
save(seuTrachea_May,file="seurat_Trachea_May.RData")
load("seurat_Trachea_May.RData")




LS0tCnRpdGxlOiAiVHJhY2hlYSBzYW1wbGUgY29sbGVjdGVkIG9uIE1heSAzIDIwMTgiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KIyMjIyBFbWJyeW9uaWMgbW91c2UgIzggRTE0LjUgd2lsZCB0eXBlCiMjIyMgc3VwcGxlbWVudGFyeQojIyMjIFNtYXJ0c2VxMiBtZXRob2QuIHJlYWRzIGFsaWduZWQgdG8gbW0xMC1wbHVzLgojIyMjI1JlYWQgdGhlIGdlbmUgY2VsbCB0YWJsZSB0aGF0IGhhcyB0aGUgcmVhZF9jb3VudCBmb3IgZXZlcnkgZ2VuZSBhbmQgY2VsbDoKYGBge3J9CnNldHdkKCIvVm9sdW1lcy9Hb29nbGVEcml2ZS9NeSBEcml2ZS9yZXNlYXJjaC9NdV9IZS9zZXF1ZW5jaW5nIikKVHJhY2hlYV9NYXk8LXJlYWQuY3N2KGZpbGU9IjE4MDUxNl9OUzUwMDEyNl8wNzk3X0FITUNLS0JHWDUuY3N2IixoZWFkZXI9VFJVRSxzZXA9IiwiKSAKYGBgCiMjIyMjUmVtb3ZlIHRoZSBmaXJzdCBjb2x1bW4gKGdlbmUgbmFtZXMpLCBhbmQgY29udmVydCB0aGUgZ2VuZSBuYW1lcyB0byByb3duYW1lcyBvZiB0aGUgZGF0YWZyYW1lCmBgYHtyfQpkZlRyYWNoZWFfTWF5PC1hcy5kYXRhLmZyYW1lKFRyYWNoZWFfTWF5WywtMV0pIApyb3duYW1lcyhkZlRyYWNoZWFfTWF5KTwtVHJhY2hlYV9NYXlbLDFdCmBgYAojIyMjI1JlbW92ZSB0aGUgbGFzdCBjb2x1bW4gKCJ1bmRldGVybWluZWQiIHJlYWRzKQpgYGB7cn0KZGZUcmFjaGVhX01heTwtZGZUcmFjaGVhX01heVssLTcwNV0gI3JlbW92ZSB0aGUgInVuZGV0ZXJtaW5lZCIgY29sdW1uCmBgYAojIyMjI2dvdCBhIGRhdGFmcmFtZSBvZiA3MDQgdmFyaWFibGVzIChjb2x1bW5zKSxiZWNhdXNlIHdlIGhhdmUgMiBwbGF0ZXMgZWFjaCBoYXZlIDM1MiAiY2VsbHMiLiBFYWNoIG9mIHRoZSBjb2x1bW4gaW4gdGhlIGRhdGFmcmFtZSBpcyBhIGNlbGwKIyMjIyNBbHNvIHRoaXMgZGF0YWZyYW1lIGhhcyAyMzQzOCBvYnNlcnZhdGlvbnMgKHJvd3MpLCBlYWNoIG9mIHdoaWNoIGlzIGEgZ2VuZQoKYGBge3J9CmxpYnJhcnkoU2V1cmF0KQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KE1hdHJpeCkKYGBgCiMjIyMjU3BlY2lmeSB0aGUgcmF3ZGF0YSB0byBiZSB0YWtlbiBieSBTZXVyYXQ6CgpgYGB7cn0KcmF3LmRhdGE8LWRmVHJhY2hlYV9NYXkKYGBgCgojIyMjI2FuYWx5emUgRVJDQzoKIyMjIyNnZXQgYWxsIHJvd25hbWVzIHRoYXQgY29udGFpbiAiRVJDQyI6CmBgYHtyfQplcmNjcyA8LSBncmVwKHBhdHRlcm4gPSAiXkVSQ0MtIiwgeCA9IHJvd25hbWVzKHggPSByYXcuZGF0YSksIHZhbHVlID0gVFJVRSkKYGBgCgojIyMjI2NhbGN1bGF0ZSB0aGUgcGVyY2VudGFnZSBvZiBFUkNDIHJlYWRzIGluIHRvdGFsIHJlYWRzIGZvciBlYWNoIGNlbGwsIGFuZCBwbG90OgpgYGB7cn0KcGVyY2VudC5lcmNjIDwtIE1hdHJpeDo6Y29sU3VtcyhyYXcuZGF0YVtlcmNjcywgXSkvTWF0cml4Ojpjb2xTdW1zKHJhdy5kYXRhKQpkZl9lcmNjPC1hcy5kYXRhLmZyYW1lKGNiaW5kKGNvbG5hbWVzKHJhdy5kYXRhKSxhcy5udW1lcmljKHBlcmNlbnQuZXJjYykpKQpnZ3Bsb3QoZGZfZXJjYyxhZXMocGVyY2VudC5lcmNjKSkrZ2VvbV9kZW5zaXR5KCkKYGBgCgojIyMjIyNHZXQgdGhlIHJvdyBpbmRleCBmb3IgRVJDQ3M6CmBgYHtyfQplcmNjLmluZGV4IDwtIGdyZXAocGF0dGVybiA9ICJeRVJDQy0iLCB4ID0gcm93bmFtZXMoeCA9IHJhdy5kYXRhKSwgdmFsdWUgPSBGQUxTRSkKYGBgCgojIyMjIyNyZW1vdmUgRVJDQ3MgZnJvbSB0aGUgZGF0YXNldCAoYnV0IHRoZSBwZXJjZW50LkVSQ0Mgd2lsbCBiZSBrZXB0IGFzIGEgbWV0YWRhdGEgY29sdW1uKToKYGBge3J9CnJhdy5kYXRhIDwtIHJhdy5kYXRhWy1lcmNjLmluZGV4LF0KYGBgCgojIyMjI05vdyBjcmVhdGUgc2V1cmF0IG9iamVjdC4KYGBge3J9CnNldVRyYWNoZWFfTWF5IDwtIENyZWF0ZVNldXJhdE9iamVjdChyYXcuZGF0YSA9IHJhdy5kYXRhLCBwcm9qZWN0ID0gIlRyYWNoZWFfTWF5X21vdXNlOCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtaW4uY2VsbHMgPSAxLCBtaW4uZ2VuZXMgPSA1MDApCmBgYApgYGB7cn0KZGltKHNldVRyYWNoZWFfTWF5QHJhdy5kYXRhKQpgYGAKIyMjIyNTbyBJIGhhdmUgNTIzICJjZWxscyIgaW4gd2hpY2ggYXQgbGVhc3QgNTAwIGdlbmVzIGFyZSBkZXRlY3RlZC4gMTgxNTcgImdlbmVzIiBhcmUgZGV0ZWN0ZWQgaW4gYXQgbGVhc3QgMSAiY2VsbCIKCiMjIyMjQWRkIHNvbWUgbWV0YSBkYXRhIHRvIHRoZSBzZXVyYXQgb2JqZWN0OgpgYGB7cn0Kc2V1VHJhY2hlYV9NYXkgPC0gQWRkTWV0YURhdGEob2JqZWN0ID0gc2V1VHJhY2hlYV9NYXksIHBlcmNlbnQuZXJjYywgY29sLm5hbWUgPSAicGVyY2VudC5lcmNjIikKCiNzZXVyYXQgd2FzIHdyaXR0ZW4gZm9yIGRyb3Atc2VxLzEwWCwgaW4gd2hpY2ggblVNSSBpcyB1c2VkIGZvciBxdWFudGlmaWNhdGlvbi4gV2UgdXNlIG51bWJlciBvZiByZWFkcyBmb3IgcXVhbnRpZmljYXRpb24gaW5zdGVhZDoKY29sbmFtZXMoc2V1VHJhY2hlYV9NYXlAbWV0YS5kYXRhKVtjb2xuYW1lcyhzZXVUcmFjaGVhX01heUBtZXRhLmRhdGEpID09ICduVU1JJ10gPC0gJ25SZWFkcycKYGBgCgojIyMjI05vdyBhbmFseXplIHJpYm9zb21lIGdlbmVzOgojIyMjIyNnZW5lcmF0ZSBhIGxpc3Qgb2YgcmlibyBnZW5lIG5hbWVzOgpgYGB7cn0Kcmliby5nZW5lcyA8LSBncmVwKHBhdHRlcm4gPSAiXlJwW3NsXVtbOmRpZ2l0Ol1dIiwgeCA9IHJvd25hbWVzKHggPSBzZXVUcmFjaGVhX01heUBkYXRhKSwgdmFsdWUgPSBUUlVFKQpgYGAKIyMjIyMjY2FsY3VsYXRlIHRoZWlyIHJhdGlvIGZvciBldmVyeSBjZWxsOgpgYGB7cn0KcGVyY2VudC5yaWJvIDwtIE1hdHJpeDo6Y29sU3VtcyhzZXVUcmFjaGVhX01heUByYXcuZGF0YVtyaWJvLmdlbmVzLCBdKS9NYXRyaXg6OmNvbFN1bXMoc2V1VHJhY2hlYV9NYXlAcmF3LmRhdGEpCmBgYAoKIyMjIyMjTm93IGFkZCBhIGNvbHVtbiBmb3IgcGVyY2VudC5yaWJvIGFzIG1ldGFkYXRhOgpgYGB7cn0Kc2V1VHJhY2hlYV9NYXkgPC0gQWRkTWV0YURhdGEob2JqZWN0ID0gc2V1VHJhY2hlYV9NYXksIG1ldGFkYXRhID0gcGVyY2VudC5yaWJvLCBjb2wubmFtZSA9ICJwZXJjZW50LnJpYm8iKQpgYGAKCiMjIyMjc2FuaXR5IGNoZWNrOgpgYGB7cn0KVmxuUGxvdChvYmplY3QgPSBzZXVUcmFjaGVhX01heSwgZmVhdHVyZXMucGxvdCA9IGMoIm5HZW5lIiwgIm5SZWFkcyIsICJwZXJjZW50LmVyY2MiLCJwZXJjZW50LnJpYm8iKSwgbkNvbCA9IDQseC5sYWIucm90ID0gVFJVRSkKYGBgCmBgYHtyfQpHZW5lUGxvdChvYmplY3QgPSBzZXVUcmFjaGVhX01heSwgZ2VuZTEgPSAiblJlYWRzIiwgZ2VuZTIgPSAibkdlbmUiLCB1c2UucmF3PVQpCmBgYAoKIyMjIyNOb3cgcmVtb3ZlIHRoZSBjZWxscyB3aXRoIHRvbyBmZXcgcmVhZHMgPDEwMGsgYW5kIHRvbyBmZXcgZ2VuZXMgPDUwMApgYGB7cn0Kc2V1VHJhY2hlYV9NYXkgPC0gRmlsdGVyQ2VsbHMob2JqZWN0ID0gc2V1VHJhY2hlYV9NYXksIHN1YnNldC5uYW1lcyA9IGMoIm5HZW5lIiwgIm5SZWFkcyIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBsb3cudGhyZXNob2xkcyA9IGMoNTAwLCAxMDAwMDApLCBoaWdoLnRocmVzaG9sZHMgPSBjKEluZiwgSW5mKSkKYGBgCmBgYHtyfQpkaW0oc2V1VHJhY2hlYV9NYXlAZGF0YSkKYGBgCgojIyMjI05vdyBub3JtYWxpemUgdGhlIGdlbmUgZXhwcmVzc2lvbiBtZWFzdXJlbWVudHMgZm9yIGVhY2ggY2VsbCBieSB0aGUgdG90YWwgZXhwcmVzc2lvbiAoc28gaXQgaXMgIyBvZiByZWFkcyBmb3IgdGhpcyBnZW5lIGRpdmlkZWQgYnkgblJlYWRzIGZvciB0aGF0IGNlbGwpLCBtdWx0aXBseSB0aGlzIGJ5IGEgc2NhbGUgZmFjdG9yICgxMCwwMDAgYnkgZGVmYXVsdCksIGxvZy10cmFuc2Zvcm0gKGxvZzFwKHgpLCB3aGljaCBpcyBsb2coMSt4KSkgdGhlIHJlc3VsdCwgYW5kIHRoZW4gc2F2ZSB0aGUgcmVzdWx0IGlzIGluIFNOcl9NYXJAZGF0YQoKYGBge3J9CnNldVRyYWNoZWFfTWF5IDwtIE5vcm1hbGl6ZURhdGEob2JqZWN0ID0gc2V1VHJhY2hlYV9NYXkpCmBgYAoKIyMjIyNOb3cgc2NhbGUgdGhlIGRhdGE6IFRoZSBzY2FsZS5kYXRhIHNsb3QgKG9iamVjdEBzY2FsZS5kYXRhKSByZXByZXNlbnRzIGEgY2VsbOKAmXMgcmVsYXRpdmUgZXhwcmVzc2lvbiBvZiBlYWNoIGdlbmUsIGluIGNvbXBhcmlzb24gdG8gYWxsIG90aGVyIGNlbGxzLiBTbyB2YWx1ZSAwIGluIHRoZSBzY2FsZS5kYXRhIG1lYW5zIGF2ZXJhZ2UgZXhwcmVzc2lvbiBsZXZlbCBmb3IgdGhhdCBnZW5lIGFjcm9zcyBhbGwgY2VsbHMuIFRoZSBtb3JlIHBvc2l0aXZlLCB0aGUgaGlnaGVyIHRoYXQgZ2VuZSBpcyBleHByZXNzZWQgaW4gdGhhdCBjZWxsLiBUaGUgdmFsdWVzIGFyZSByZS1jZW50ZXJlZCBmb3IgZWFjaCBnZW5lLiBUaGlzIGRhdGEgaXMgdXNlZCBhcyBpbnB1dCBmb3IgZGltZW5zaW9uYWwgcmVkdWN0aW9uIHRlY2huaXF1ZXMsIGFuZCBpcyBkaXNwbGF5ZWQgaW4gaGVhdG1hcHMuCmBgYHtyfQojaWYgd2FudCB0byByZWdyZXNzIG91dCBzb21lIGZhY3RvcnMsIHVzZSBpbiB0aGUgU2NhbGVEYXRhIGZ1bmN0aW9uOiB2YXJzLnRvLnJlZ3Jlc3MgPSBjKCJuUmVhZHMiLCAicGVyY2VudC5lcmNjIiwiUm40NXMiLCJuR2VuZSIpCiNIZXJlIGxldCdzIG5vdCByZWdyZXNzIG91dCBhbnl0aGluZyBhbmQgdGFrZSBhIGxvb2sKc2V1VHJhY2hlYV9NYXkgPC0gU2NhbGVEYXRhKG9iamVjdCA9IHNldVRyYWNoZWFfTWF5KQpgYGAKCmBgYHtyfQpzZXVUcmFjaGVhX01heSA8LSBGaW5kVmFyaWFibGVHZW5lcyhvYmplY3QgPSBzZXVUcmFjaGVhX01heSwgZG8ucGxvdCA9IFRSVUUsIHguaGlnaC5jdXRvZmYgPSBJbmYsIHkuY3V0b2ZmID0gMC41KQpgYGAKIyMjIyNUaGUgYWJvdmUgZ2VuZXJhdHMgb2JqZWN0QHZhci5nZW5lcywgd2hpY2ggaXMgYSB2ZWN0b3Igb2YgZ2VuZSBuYW1lcyB0aGF0IGFyZSBpZGVudGlmaWVkIHRvIGJlIHZhcmlhYmxlLiB5LmN1dG9mZiBkZWNpZGVzIHRoZSBjdXRvZmYgZm9yIGJlaW5nICJ2YXJpYWJsZSIuCiMjIyMjI1RoZSByZXN1bHQgb2YgYWxsIGFuYWx5c2lzIGlzIHN0b3JlZCBpbiBvYmplY3RAaHZnLmluZm8uIEEgcGxvdCBpcyBhbHNvIGdlbmVyYXRlZCwgd2l0aCAidmFyaWFibGUiIGdlbmVzIGxhYmVsZWQgd2l0aCBuYW1lcy4KCiMjIyMjI3J1biBQQ0Egb24gdGhlIHNldCBvZiBnZW5lcyBkZWNpZGVkIGluIHNvX1NOckB2YXIuZ2VuZXM6CiMjIyMjI1JldHVybnMgU2V1cmF0IG9iamVjdCB3aXRoIHRoZSBQQ0EgY2FsY3VsYXRpb24gc3RvcmVkIGluIG9iamVjdEBkciRwY2EuIEluIHRoZSBmdW5jdGlvbiBiZWxvdywgaWYgZG8ucHJpbnQ9VFJVRSwgZ2VuZXMgaW4gZWFjaCBQQyB3aWxsIGJlIHNob3duLgpgYGB7cn0Kc2V1VHJhY2hlYV9NYXkgPC0gUnVuUENBKG9iamVjdCA9IHNldVRyYWNoZWFfTWF5LCBkby5wcmludCA9IEZBTFNFKQpQQ0FQbG90KHNldVRyYWNoZWFfTWF5KQpgYGAKIyMjIyNQcm9qZWN0UENBIHNjb3JlcyBlYWNoIGdlbmUgaW4gdGhlIGRhdGFzZXQgKGluY2x1ZGluZyBnZW5lcyBub3QgaW5jbHVkZWQgaW4gdGhlIFBDQSkgYmFzZWQgb24gdGhlaXIgY29ycmVsYXRpb24gd2l0aCB0aGUgY2FsY3VsYXRlZCBjb21wb25lbnRzLiBUaG91Z2ggd2UgZG9u4oCZdCB1c2UgdGhpcyBmdXJ0aGVyIGhlcmUsIGl0IGNhbiBiZSB1c2VkIHRvIGlkZW50aWZ5IG1hcmtlcnMgdGhhdCBhcmUgc3Ryb25nbHkgY29ycmVsYXRlZCB3aXRoIGNlbGx1bGFyIGhldGVyb2dlbmVpdHksIGJ1dCBtYXkgbm90IGhhdmUgcGFzc2VkIHRocm91Z2ggdmFyaWFibGUgZ2VuZSBzZWxlY3Rpb24uIFRoZSByZXN1bHRzIG9mIHRoZSBwcm9qZWN0ZWQgUENBIGNhbiBiZSBleHBsb3JlZCBieSBzZXR0aW5nIHVzZS5mdWxsPVQgaW4gdGhlIGZ1bmN0aW9ucyBiZWxvdy4KYGBge3J9CnNldVRyYWNoZWFfTWF5IDwtIFByb2plY3RQQ0Eob2JqZWN0ID0gc2V1VHJhY2hlYV9NYXksIGRvLnByaW50ID0gVFJVRSkKYGBgCiMjIyMjQW5vdGhlciB3YXkgdG8gc2hvdyBtYWpvciBnZW5lcyBpbiBtYWpvciBQQ3M6CmBgYHtyfQpQcmludFBDQShzZXVUcmFjaGVhX01heSwgcGNzLnByaW50ID0gMTo1LCBnZW5lcy5wcmludCA9IDUsIHVzZS5mdWxsID0gVFJVRSkKYGBgCiMjIyMjQmVsb3cgaXMgYW5vdGhlciB3YXkgdG8gc2VlIFBDcyBhbmQgaG93IHRoZXkgc2VwYXJhdGUgdGhlIGRhdGE6IGNlbGxzIGFuZCBnZW5lcyBhcmUgb3JkZXJlZCBhY2NvcmRpbmcgdG8gdGhlaXIgUENBIHNjb3Jlcy4gU2V0dGluZyBjZWxscy51c2UgKGZvciBleGFtcGxlOiBjZWxsLnVzZT0xMDApIHRvIGEgbnVtYmVyIHBsb3RzIHRoZSDigJhleHRyZW1l4oCZIGNlbGxzIG9uIGJvdGggZW5kcyBvZiB0aGUgc3BlY3RydW0sIHdoaWNoIGRyYW1hdGljYWxseSBzcGVlZHMgcGxvdHRpbmcgZm9yIGxhcmdlIGRhdGFzZXRzIChidXQgd2lsbCBpZ25vcmUgdGhlIGNlbGxzIGluIHRoZSBtaWRkbGUpLiBudW0uZ2VuZXM9MzAgYnkgZGVmYXVsdC4KYGBge3J9ClBDSGVhdG1hcChvYmplY3QgPSBzZXVUcmFjaGVhX01heSwgcGMudXNlID0gMTozLCBkby5iYWxhbmNlZCA9IFRSVUUsIGxhYmVsLmNvbHVtbnMgPSBGQUxTRSkKYGBgCiMjIyMjTm93IG5lZWQgdG8gZGVjaWRlIGhvdyBtYW55IFBDcyB0byB1c2U6CmBgYHtyfQpQQ0VsYm93UGxvdChvYmplY3QgPSBzZXVUcmFjaGVhX01heSkKYGBgCiMjIyMjI1RoZSBhYm92ZSBwbG90IHNob3dzIHRoYXQgdGhlIGVsYm93IG9mIHRoZSBncmFwaCBmYWxscyBhdCBhcm91bmQgcGMgMjAuCiMjIyMjI0Fub3RoZXIgd2F5IHRvIHN0YXRpc3RpY2FsbHkgZXN0aW1hdGU6IChjYXV0aW9uOiBydW5uaW5nIHRoaXMgaXMgc2xvdykKYGBge3J9CnNldVRyYWNoZWFfTWF5IDwtIEphY2tTdHJhdyhzZXVUcmFjaGVhX01heSwgbnVtLnJlcGxpY2F0ZSA9IDEwMCwgZG8ucHJpbnQgPSBGQUxTRSkKSmFja1N0cmF3UGxvdChzZXVUcmFjaGVhX01heSwgUENzID0gMToyMCkKYGBgCgpgYGB7cn0Kbi5wY3MgPSAyMApgYGAKIyMjIyNyZXNvbHV0aW9uIHBhcmFtZXRlciBzZXRzIHRoZSDigJhncmFudWxhcml0eeKAmSBvZiB0aGUgZG93bnN0cmVhbSBjbHVzdGVyaW5nLCB3aXRoIGluY3JlYXNlZCB2YWx1ZXMgbGVhZGluZyB0byBhIGdyZWF0ZXIgbnVtYmVyIG9mIGNsdXN0ZXJzLiAKYGBge3J9CnJlcy51c2VkIDwtIDEKYGBgCiMjIyMjSy1uZWFyZXN0IG5laWdoYm9yOiAKYGBge3J9CnNldVRyYWNoZWFfTWF5IDwtIEZpbmRDbHVzdGVycyhvYmplY3QgPSBzZXVUcmFjaGVhX01heSwgcmVkdWN0aW9uLnR5cGUgPSAicGNhIiwgZGltcy51c2UgPSAxOm4ucGNzLCAKICAgICAgICAgICAgICAgICAgICAgcmVzb2x1dGlvbiA9IHJlcy51c2VkLCBwcmludC5vdXRwdXQgPSAwLCBmb3JjZS5yZWNhbGMgPSBUKQpgYGAKIyMjIyNMZXQncyBleHRyYWN0IHBsYXRlIGFuZCBpbmRleCBpbmZvcm1hdGlvbiBmcm9tIHRoZSBjZWxsIG5hbWVzIChjb2x1bW4gbmFtZXMpIGFuZCBtYWtlIHRoZW0gcGFydCBvZiB0aGUgbWV0YSBkYXRhCmBgYHtyfQpjZWxsX25hbWU8LXJlYWQudGFibGUodGV4dD1uYW1lcyhzZXVUcmFjaGVhX01heUBpZGVudCksc2VwPSJfIixjb2xDbGFzc2VzID0gImNoYXJhY3RlciIpCnRhYmxlKGNlbGxfbmFtZVssMV0pCmNvbG5hbWVzKGNlbGxfbmFtZSk8LWMoInBsYXRlIiwid2VsbCIsInRpc3N1ZSIsIm90aGVyIikKYGBgCiMjIyMjTm93IEkgY2FuIHNlZSBob3cgbWFueSBjZWxsIHBhc3NpbmcgZmlsdGVycyBmcm9tIGVhY2ggcGxhdGUuCgojIyMjI05vdyBsZXQncyBtYWtlIHRoZSAicGxhdGUiIGluZm9ybWF0aW9uIHBhcnQgb2YgZWFjaCBjZWxsJ3MgbWV0YWRhdGE6CmBgYHtyfQpwbGF0ZTwtY2VsbF9uYW1lJHBsYXRlCm5hbWVzKHBsYXRlKTwtbmFtZXMoc2V1VHJhY2hlYV9NYXlAaWRlbnQpICAgI0FkZE1ldGFEYXRhIG5lZWRzIG5hbWVzIHRvIGFzc2lnbiB2YWx1ZXMKc2V1VHJhY2hlYV9NYXk8LUFkZE1ldGFEYXRhKG9iamVjdCA9IHNldVRyYWNoZWFfTWF5LCBtZXRhZGF0YSA9IHBsYXRlLCBjb2wubmFtZSA9ICJwbGF0ZSIpCmBgYAoKIyMjIyN0U05FOiAocGVycGxleGl0eSBkZWZhdWx0IGlzIDMwKQpgYGB7cn0Kc2V1VHJhY2hlYV9NYXkgPC0gUnVuVFNORShvYmplY3QgPSBzZXVUcmFjaGVhX01heSwgZGltcy51c2UgPSAxOm4ucGNzLCBwZXJwbGV4aXR5PTMwKQpgYGAKYGBge3J9ClRTTkVQbG90KG9iamVjdCA9IHNldVRyYWNoZWFfTWF5LCBkby5sYWJlbCA9IFQpCmBgYAoKYGBge3J9ClRTTkVQbG90KG9iamVjdCA9IHNldVRyYWNoZWFfTWF5LCBncm91cC5ieT0icGxhdGUiKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTJ9CkZlYXR1cmVQbG90KHNldVRyYWNoZWFfTWF5LCBjKCJuR2VuZSIsIkdmcF90cmFuc2dlbmUiLCJUZHRvbV90cmFuc2dlbmUiLCJTaGgiLCJBbm8xIiwiRXBjYW0iLCJMdW0iLCJBdXJrYiIsIk1hdG40IiwiRXNhbSIsIkFjdGMxIiwiUGF4OCIpLCBwdC5zaXplID0gMC45LCBuQ29sID0gMyxuby5sZWdlbmQgPSBGKQpgYGAKYGBge3J9CnNldVRyYWNoZWFfTWF5IDwtIFNldEFsbElkZW50KG9iamVjdCA9IHNldVRyYWNoZWFfTWF5LCBpZCA9ICJpZGVudCIpCmBgYAoKYGBge3J9CkdlbmVQbG90KG9iamVjdCA9IHNldVRyYWNoZWFfTWF5LCBnZW5lMSA9ICJTaGgiLCBnZW5lMiA9ICJHZnBfdHJhbnNnZW5lIiwgdXNlLnJhdz1UKQpgYGAKYGBge3IsZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTJ9ClZsblBsb3Qob2JqZWN0ID0gc2V1VHJhY2hlYV9NYXksIGZlYXR1cmVzLnBsb3QgPSBjKCJHZnBfdHJhbnNnZW5lIiwiVGR0b21fdHJhbnNnZW5lIiwgIkNyZV90cmFuc2dlbmUiKSwgbkNvbCA9IDMpCmBgYAoKCmBgYHtyfQpEb0hlYXRtYXAob2JqZWN0ID0gc2V1VHJhY2hlYV9NYXksIGdlbmVzLnVzZSA9IGMoIlRkdG9tX3RyYW5zZ2VuZSIsIkNyZV90cmFuc2dlbmUiLCAiR2ZwX3RyYW5zZ2VuZSIsIlNoaCIsIkFubzEiLCJTb3g5IiksIAogICAgc2xpbS5jb2wubGFiZWwgPSBUUlVFLCBncm91cC5sYWJlbC5yb3QgPSBUUlVFKQpgYGAKCiMjIyMjZmluZCBtYXJrZXJzIGZvciBldmVyeSBjbHVzdGVyIGNvbXBhcmVkIHRvIGFsbCByZW1haW5pbmcgY2VsbHMsIHJlcG9ydCBvbmx5IHRoZSBwb3NpdGl2ZSBvbmVzCmBgYHtyfQpjbHVzdGVyLm1hcmtlcnMgPC0gRmluZEFsbE1hcmtlcnMob2JqZWN0PXNldVRyYWNoZWFfTWF5LCBtaW4ucGN0ID0gMC4yLG9ubHkucG9zPVRSVUUpCmNsdXN0ZXIubWFya2VycyAlPiUgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIHRvcF9uKDEwLCBhdmdfbG9nRkMpCmBgYAojIyMjI2NvbXBhcmUgY2x1c3RlciAwIGFuZCAyCmBgYHtyfQpjbHVzdGVyMC5tYXJrZXJzLnBvcyA8LSBGaW5kTWFya2VycyhzZXVUcmFjaGVhX01heSwgaWRlbnQuMSA9IDAsaWRlbnQuMiA9IDIsIG1pbi5wY3QgPSAwLG9ubHkucG9zPVRSVUUpCnByaW50KGNsdXN0ZXIwLm1hcmtlcnMucG9zKQpgYGAKYGBge3J9CmNsdXN0ZXIyLm1hcmtlcnMucG9zIDwtIEZpbmRNYXJrZXJzKHNldVRyYWNoZWFfTWF5LCBpZGVudC4xID0gMixpZGVudC4yID0gMCwgbWluLnBjdCA9IDAsb25seS5wb3M9VFJVRSkKcHJpbnQoY2x1c3RlcjIubWFya2Vycy5wb3MpCmBgYAoKIyMjIyNzYXZlIHRoZSBzZXVyYXQgcHJvamVjdCBmb3IgZnV0dXJlIHZpc2l0OgpgYGB7cn0Kc2F2ZShzZXVUcmFjaGVhX01heSxmaWxlPSJzZXVyYXRfVHJhY2hlYV9NYXkuUkRhdGEiKQpsb2FkKCJzZXVyYXRfVHJhY2hlYV9NYXkuUkRhdGEiKQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0PTEyLCBmaWcud2lkdGg9MTZ9CkZlYXR1cmVQbG90KHNldVRyYWNoZWFfTWF5LCBjKCJHZnBfdHJhbnNnZW5lIiwiVGR0b21fdHJhbnNnZW5lIiwiVHJwbTUiLCJBbm8xIiwiQW5vNyIsIlBsY2IyIiwiSWwyNSIsIkRiaCIsIlNveDkiKSwgcHQuc2l6ZSA9IDAuNiwgbkNvbCA9IDMsbm8ubGVnZW5kID0gRikKYGBgCmBgYHtyLGZpZy5oZWlnaHQ9NiwgZmlnLndpZHRoPTEyfQpWbG5QbG90KG9iamVjdCA9IHNldVRyYWNoZWFfSnVuLCBmZWF0dXJlcy5wbG90ID0gYygiR2ZwX3RyYW5zZ2VuZSIsIlRkdG9tX3RyYW5zZ2VuZSIpLCBuQ29sID0gMSx4LmxhYi5yb3QgPSBUUlVFKQpgYGAKYGBge3IsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTE0fQpEb0hlYXRtYXAob2JqZWN0ID0gc2V1VHJhY2hlYV9NYXksIGdlbmVzLnVzZSA9IGMoICJHZnBfdHJhbnNnZW5lIiwiVGR0b21fdHJhbnNnZW5lIiwiRXBjYW0iLCJDcmVfdHJhbnNnZW5lIiksIAogICAgc2xpbS5jb2wubGFiZWwgPSBUUlVFLCBncm91cC5sYWJlbC5yb3QgPSBUUlVFKQpgYGAKYGBge3IsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTE0fQpEb0hlYXRtYXAob2JqZWN0ID0gc2V1VHJhY2hlYV9NYXksIGdlbmVzLnVzZSA9IGMoICJHZnBfdHJhbnNnZW5lIiwiVGR0b21fdHJhbnNnZW5lIiwiRXBjYW0iLCJDcmVfdHJhbnNnZW5lIiksIAogICAgc2xpbS5jb2wubGFiZWwgPSBUUlVFLCBncm91cC5sYWJlbC5yb3QgPSBUUlVFLHVzZS5zY2FsZWQgPSBGKQpgYGAKCiMjIyMgTWFwIHNvcnRpbmcgZGF0YSB0byBzZXF1ZW5jaW5nIGRhdGE6CiMjIyMjUmVhZCBpbmRleCBkYXRhOgpgYGB7cn0KQjAwMzkzODwtcmVhZC5jc3YoZmlsZT0iVHJhY2hlYV9CMDAzOTM4LmNzdiIsaGVhZGVyPVRSVUUsc2VwPSIsIixzdHJpbmdzQXNGYWN0b3JzID0gRikKQjAwMzkzOF9zb3J0PC1CMDAzOTM4W0IwMDM5MzgkSW5kZXghPSIiLF0KQjAwMzkzNTwtcmVhZC5jc3YoZmlsZT0iVHJhY2hlYV9CMDAzOTM1LmNzdiIsaGVhZGVyPVRSVUUsc2VwPSIsIixzdHJpbmdzQXNGYWN0b3JzID0gRikKQjAwMzkzNV9zb3J0PC1CMDAzOTM1W0IwMDM5MzUkSW5kZXghPSIiLF0KYGBgCgojIyMjI0V4dHJhY3QgZXhwcmVzc2lvbiBsZXZlbHMgb2YgZ2VuZXMuIE1ha2UgYSBkYXRhZnJhbWUgKGNsdXN0ZXJfY2VsbCkgdGhhdCBoYXMgdGhlIHBsYXRlICMsIGluZGV4IywgY2x1c3RlciBpZGVudGl0eSwgYW5kIGV4cHJlc3Npb24gbGV2ZWxzIG9mIHNvbWUgZ2VuZXMKYGBge3J9ClRkdG9tYXRvPC1zZXVUcmFjaGVhX01heUBkYXRhW3doaWNoKHJvd25hbWVzKHNldVRyYWNoZWFfTWF5QGRhdGEpPT0iVGR0b21fdHJhbnNnZW5lIiksXQpHZnA8LXNldVRyYWNoZWFfTWF5QGRhdGFbd2hpY2gocm93bmFtZXMoc2V1VHJhY2hlYV9NYXlAZGF0YSk9PSJHZnBfdHJhbnNnZW5lIiksXQpjbHVzdGVyX2NlbGw8LWNiaW5kKGNlbGxfbmFtZVssMToyXSxzZXVUcmFjaGVhX01heUBpZGVudCxUZHRvbWF0byxHZnApCmNvbG5hbWVzKGNsdXN0ZXJfY2VsbCk8LWMoInBsYXRlIiwiSW5kZXgiLCJpZGVudGl0eSIsIlRkdG9tX3RyYW5zZ2VuZSIsIkdmcF90cmFuc2dlbmUiKQpgYGAKCiMjIyMjI3NwZWNpZnkgcGxhdGUjIGluIHNvcnRpbmcgbWV0YWRhdGEKYGBge3J9CkIwMDM5MzVfc29ydCRwbGF0ZTwtcmVwKCJCMDAzOTM1IiwzNTIpCiNtZXJnZV9CMDAzOTM1PC1tZXJnZShjbHVzdGVyX2NlbGwsQjAwMzkzNV9zb3J0KQpgYGAKCmBgYHtyfQojbG93UV9CMDAzOTM1IDwtIGFudGlfam9pbihCMDAzOTM1X3NvcnQsY2x1c3Rlcl9jZWxsLGJ5PWMoInBsYXRlIiwiSW5kZXgiKSkKYGBgCgpgYGB7cn0Kam9pbl9CMDAzOTM1PC1sZWZ0X2pvaW4oQjAwMzkzNV9zb3J0LGNsdXN0ZXJfY2VsbCkKYGBgCmBgYHtyfQp0YWJsZShqb2luX0IwMDM5MzUkaWRlbnRpdHksZXhjbHVkZT1OVUxMKQpgYGAKIyMjIyMjIE5BIGluIHRoZSBpZGVudGl0eSBjb2x1bW4gbWVhbnMgdGhvc2UgImNlbGxzIiBkaWQgbm90IHBhc3MgdGhlIGZpbHRlcmluZyBjcml0ZXJpYSBhYm92ZSAobkdlbmUgNTAwLCBuUmVhZHMgMTAwayBldGMuLikKYGBge3J9CmdncGxvdChqb2luX0IwMDM5MzUsYWVzKHg9bG9nMTAoSG9lY2hzdC4zMzM0Mi5BLkNvbXBlbnNhdGVkKSkpK2dlb21fZGVuc2l0eShhZXMoY29sb3I9aWRlbnRpdHkpKQpgYGAKIyMjIyMjIFNvIHRob3NlIEhvZWNoc3Qgc3VwZXIgaGlnaCBqdW5rIHRlbmQgdG8gaGF2ZSBpbnRlcm1lZGlhdGUtaGlnaCBsZXZlbCBvZiBFR0ZQOgpgYGB7cn0KZ2dwbG90KGpvaW5fQjAwMzkzNSxhZXMoeD1sb2cxMChIb2VjaHN0LjMzMzQyLkEuQ29tcGVuc2F0ZWQpLHk9bG9nMTAoRUdGUC5BLkNvbXBlbnNhdGVkKSkpK2dlb21fcG9pbnQoYWVzKGNvbG9yPWlkZW50aXR5KSkKYGBgCiMjIyMjIyBBbmQgdGhlIEhvZWNoc3Qgc3VwZXIgaGlnaCBqdW5rIHRlbmQgdG8gaGF2ZSByZWxhdGl2ZWx5IGxvdyB0ZFRvbWF0byBzaWduYWw6CmBgYHtyfQpnZ3Bsb3Qoam9pbl9CMDAzOTM1LGFlcyh4PWxvZzEwKEhvZWNoc3QuMzMzNDIuQS5Db21wZW5zYXRlZCkseT1sb2cxMCh0ZFRvbWF0by5BLkNvbXBlbnNhdGVkKSkpK2dlb21fcG9pbnQoYWVzKGNvbG9yPWlkZW50aXR5KSkKYGBgCmBgYHtyfQpnZ3Bsb3Qoam9pbl9CMDAzOTM1LGFlcyh4PWxvZzEwKEVHRlAuQS5Db21wZW5zYXRlZCkseT1sb2cxMCh0ZFRvbWF0by5BLkNvbXBlbnNhdGVkKSkpK2dlb21fcG9pbnQoYWVzKGNvbG9yPWlkZW50aXR5KSxzaXplPTAuMikKYGBgCiMjIyMjIyBBbmQgdGhlIE5BICJjZWxscyIiIHRlbmRzIHRvIGJlIHZlcnkgc21hbGwgaW4gdGVybXMgb2YgRlNDLlc6CmBgYHtyfQpnZ3Bsb3Qoam9pbl9CMDAzOTM1LGFlcyhsb2cxMChFR0ZQLkEuQ29tcGVuc2F0ZWQpLEZTQy5XKSkrZ2VvbV9wb2ludChhZXMoY29sb3I9aWRlbnRpdHkpKQpgYGAKYGBge3J9CmdncGxvdChqb2luX0IwMDM5MzUsYWVzKGxvZzEwKHRkVG9tYXRvLkEuQ29tcGVuc2F0ZWQpLEZTQy5XKSkrZ2VvbV9wb2ludChhZXMoY29sb3I9aWRlbnRpdHkpKQpgYGAKCmBgYHtyfQpnZ3Bsb3Qoam9pbl9CMDAzOTM1LGFlcyhGU0MuQSxsb2cxMChCU0MuQSkpKStnZW9tX3BvaW50KGFlcyhjb2xvcj1pZGVudGl0eSkpCmBgYApgYGB7cn0KZ2dwbG90KGpvaW5fQjAwMzkzNSxhZXMoRlNDLkEsbG9nMTAoSG9lY2hzdC4zMzM0Mi5BLkNvbXBlbnNhdGVkKSkpK2dlb21fcG9pbnQoYWVzKGNvbG9yPWlkZW50aXR5KSkKYGBgCmBgYHtyfQpnZ3Bsb3Qoc3Vic2V0KGpvaW5fQjAwMzkzNSwhaXMubmEoR2ZwX3RyYW5zZ2VuZSkpLGFlcyh4PWxvZzEwKEVHRlAuQS5Db21wZW5zYXRlZCkseT1sb2cxMCh0ZFRvbWF0by5BLkNvbXBlbnNhdGVkKSxjb2xvcj1HZnBfdHJhbnNnZW5lKSkrZ2VvbV9wb2ludChzaXplPTAuMykrc2NhbGVfY29sb3JfY29udGludW91cyhsb3c9InllbGxvdyIsaGlnaD0iQmxhY2siKQpgYGAKYGBge3J9CmdncGxvdChzdWJzZXQoam9pbl9CMDAzOTM1LCFpcy5uYShUZHRvbV90cmFuc2dlbmUpKSxhZXMoeD1sb2cxMChFR0ZQLkEuQ29tcGVuc2F0ZWQpLHk9bG9nMTAodGRUb21hdG8uQS5Db21wZW5zYXRlZCksY29sb3I9VGR0b21fdHJhbnNnZW5lKSkrZ2VvbV9wb2ludChzaXplPTAuMykrc2NhbGVfY29sb3JfY29udGludW91cyhsb3c9IkJsYWNrIixoaWdoPSJ5ZWxsb3ciKQpgYGAKYGBge3J9CmdncGxvdChzdWJzZXQoam9pbl9CMDAzOTM1LCFpcy5uYShUZHRvbV90cmFuc2dlbmUpKSxhZXMoeD1sb2cxMChFR0ZQLkEuQ29tcGVuc2F0ZWQpLHk9bG9nMTAodGRUb21hdG8uQS5Db21wZW5zYXRlZCksY29sb3I9bG9nKFRkdG9tX3RyYW5zZ2VuZS9HZnBfdHJhbnNnZW5lKSkpK2dlb21fcG9pbnQoc2l6ZT0wLjMpK3NjYWxlX2NvbG9yX2NvbnRpbnVvdXMobG93PSJCbGFjayIsaGlnaD0ieWVsbG93IikKYGBgCgojIyMjIyMgSW5zdGVyZXN0aW5nbHkgY2x1c3RlciAwIGFuZCAyIG1heSBkaWZmZXIgYSBiaXQgaW4gc2l6ZXMKYGBge3J9CmdncGxvdChqb2luX0IwMDM5MzVbam9pbl9CMDAzOTM1JGlkZW50aXR5ICVpbiUgYygiMCIsIjIiKSxdLGFlcyhGU0MuVykpK2dlb21fZGVuc2l0eShhZXMoY29sb3I9aWRlbnRpdHkpKQpgYGAKCmBgYHtyfQpCMDAzOTM4X3NvcnQkcGxhdGU8LXJlcCgiQjAwMzkzOCIsMzUyKQpqb2luX0IwMDM5Mzg8LWxlZnRfam9pbihCMDAzOTM4X3NvcnQsY2x1c3Rlcl9jZWxsKQpgYGAKYGBge3J9CnRhYmxlKGpvaW5fQjAwMzkzOCRpZGVudGl0eSxleGNsdWRlPU5VTEwpCmBgYAojIyMjIyMgSW50ZXJtZWRpYXRlIEhvZWNoc3QgYW5kIGJlbG93IHdlcmUgY3V0IG9mZi4gSG9lY2hzdCBzdXBlciBoaWdoIHdlcmUgc29ydGVkLiBUaGVyZWZvcmUgd2UgZ290IHNvIG1hbnkgTkEgaW4gQjAwMzkzOApgYGB7cn0KZ2dwbG90KGpvaW5fQjAwMzkzOCxhZXMobG9nMTAoSG9lY2hzdC4zMzM0Mi5BLkNvbXBlbnNhdGVkKSkpK2dlb21fZGVuc2l0eShhZXMoY29sb3I9aWRlbnRpdHkpKQpgYGAKIyMjIyMjIEFnYWluIHRob3NlIEhvZWNoc3QgaGlnaCBqdW5rIGlzIHNtYWxsIGluIHNpemUKYGBge3J9CmdncGxvdChqb2luX0IwMDM5MzgsYWVzKHg9bG9nMTAoRUdGUC5BLkNvbXBlbnNhdGVkKSx5PWxvZzEwKHRkVG9tYXRvLkEuQ29tcGVuc2F0ZWQpKSkrZ2VvbV9wb2ludChhZXMoY29sb3I9aWRlbnRpdHkpLHNpemU9MC4yKQpgYGAKYGBge3J9CmdncGxvdChqb2luX0IwMDM5MzgsYWVzKHg9bG9nMTAoRUdGUC5BLkNvbXBlbnNhdGVkKSx5PWxvZzEwKHRkVG9tYXRvLkEuQ29tcGVuc2F0ZWQpLGNvbG9yPUdmcF90cmFuc2dlbmUpKStnZW9tX3BvaW50KHNpemU9MC4zKStzY2FsZV9jb2xvcl9jb250aW51b3VzKGxvdz0ieWVsbG93IixoaWdoPSJyZWQiKQpgYGAKYGBge3J9CmdncGxvdChqb2luX0IwMDM5MzgsYWVzKHg9bG9nMTAoRUdGUC5BLkNvbXBlbnNhdGVkKSx5PWxvZzEwKHRkVG9tYXRvLkEuQ29tcGVuc2F0ZWQpLGNvbG9yPVRkdG9tX3RyYW5zZ2VuZSkpK2dlb21fcG9pbnQoc2l6ZT0wLjMpK3NjYWxlX2NvbG9yX2NvbnRpbnVvdXMobG93PSJ5ZWxsb3ciLGhpZ2g9InJlZCIpCmBgYApgYGB7cn0KZ2dwbG90KGpvaW5fQjAwMzkzOCxhZXMobG9nMTAoRUdGUC5BLkNvbXBlbnNhdGVkKSxGU0MuVykpK2dlb21fcG9pbnQoYWVzKGNvbG9yPWlkZW50aXR5KSkKYGBgCmBgYHtyfQpnZ3Bsb3Qoam9pbl9CMDAzOTM4LGFlcyhsb2cxMCh0ZFRvbWF0by5BLkNvbXBlbnNhdGVkKSxGU0MuVykpK2dlb21fcG9pbnQoYWVzKGNvbG9yPWlkZW50aXR5KSkKYGBgCmBgYHtyfQpnZ3Bsb3Qoam9pbl9CMDAzOTM4LGFlcyhGU0MuQSxsb2cxMChIb2VjaHN0LjMzMzQyLkEuQ29tcGVuc2F0ZWQpKSkrZ2VvbV9wb2ludChhZXMoY29sb3I9aWRlbnRpdHkpKQpgYGAKCgoKCgoKCgoKCgoK